package com.ziytek.web.citizen.service.impl;

import com.google.gson.Gson;
import com.ziytek.web.citizen.config.caffeine.CaffeineUtil;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.constant.TableConstant;
import com.ziytek.web.citizen.mapper.BoardConfigMapper;
import com.ziytek.web.citizen.mapper.OperationDetailMapper;
import com.ziytek.web.citizen.mapper.TableMapper;
import com.ziytek.web.citizen.model.bean.BatteriesDetails;
import com.ziytek.web.citizen.model.req.BatteryDetailsHistoryQueryReq;
import com.ziytek.web.citizen.model.req.BatteryDetailsQueryReq;
import com.ziytek.web.citizen.model.rsp.BatteryDetailsRsp;
import com.ziytek.web.citizen.model.vo.RealTimeVo;
import com.ziytek.web.citizen.service.BatchNoService;
import com.ziytek.web.citizen.service.BatteryDetailsHistoryService;
import com.ziytek.web.citizen.service.CompressionService;
import com.ziytek.web.citizen.service.OperationVoCacheService;
import com.ziytek.web.citizen.service.itf.BatteryDetailsQueryService;
import com.ziytek.web.citizen.util.KeyUtil;
import com.ziytek.web.citizen.util.NumberToUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

/**
 * @author fenghx
 * @version v1.0
 * @className QueryBatteryDetailsServiceImp
 * @description 功能描述
 * @date 2023/8/7 13:25
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class BatteryDetailsQueryServiceImpl implements BatteryDetailsQueryService {
    private final Gson gson;
    private final TableMapper tableMapper;
    private final BatchNoService batchNoService;
    private final BoardConfigMapper boardConfigMapper;
    private final CompressionService compressionService;
    private final OperationDetailMapper operationDetailMapper;
    private final OperationVoCacheService operationVoCacheService;
    private final BatteryDetailsHistoryService batteryDetailsHistoryService;

    @Override
    public BatteryDetailsRsp batteryDetailsQuery(BatteryDetailsQueryReq request) {
        var response = new BatteryDetailsRsp();
        response.success();
        response.setDataCount(NumConstant.INT_ZERO);
        response.setPageNumCount(NumConstant.INT_ZERO);

        String door = request.getDoor();
        var lineNo = request.getLineNo();
        var limit = request.getPageSize();
        var channelNo = request.getChannelNo();
        if (StringUtils.isEmpty(request.getCabinetNo())) {
            request.setCabinetNo("0");
        }
        var cabinetNo = Integer.parseInt(request.getCabinetNo());
        var pageNum = Math.max(request.getPageNum(), NumConstant.INT_ONE);

        if (StringUtils.isEmpty(door) || lineNo == null || channelNo == null) {
            // 测试用
            //door = ServerConstant.DOOR_FRONT_LEFT;
            //lineNo = 1;
            // channelNo = 1;

            return response;
        }

        var boardConfig = boardConfigMapper.queryByDoorAndChannelNo(door, lineNo, channelNo);
        if (boardConfig == null) {
            log.error("查询电芯[{}]-[{}]-[{}]的阶段统计数据失败,原因:电芯不存在", door, lineNo, channelNo);
            //response.setRetCode("20001");
            //response.setRetMsg(ServerConstant.ERROR_MSG);
            return response;
        }

        var timestamp = getCreateTime(cabinetNo, boardConfig.getAddress(), channelNo);
        if (timestamp == null) {
            log.info("查询电芯cn[{}]-bn[{}]-cnn[{}]的阶段统计数据失败,原因:没有找到创建时间", cabinetNo, boardConfig.getAddress(), channelNo);
            return response;
        }

        var tableName = TableConstant.TABLE_REAL_TIME + boardConfig.getAddress();
        var count = tableMapper.queryRealTimeCount(tableName, cabinetNo, boardConfig.getAddress(), channelNo, timestamp);
        if (count <= NumConstant.INT_ZERO) {
            return response;
        }

        var vdo = tableMapper.queryRealTime(tableName, cabinetNo, boardConfig.getAddress(), channelNo, timestamp, pageNum * limit - limit, limit);
        //log.info("查询电芯[{}]-[{}]的阶段统计数据,总数[{}]-返回[{}]", boardConfig.getAddress(), boardConfig.getChannelNo(), count, vdo.size());

        if (CollectionUtils.isEmpty(vdo)) {
            response.setRetCode("20002");
            response.setRetMsg(ServerConstant.ERROR_MSG);
            return response;
        }

        List<BatteriesDetails> list = new ArrayList<>();
        response.setDataCount(count);
        var pageCount = (int) Math.ceil((double) count / limit);
        response.setPageNumCount(pageCount);
        for (var r : vdo) {
            byte[] data;
            try {
                data = compressionService.decompress(r.getData());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            var v = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
            if (v == null) {
                continue;
            }

            var o = new BatteriesDetails();
            o.setType(v.getCty());
            o.setC((float) v.getC());
            o.setV((float) v.getV());
            //o.setAt((long) v.getTs());
            o.setAt(r.getTime());
            o.setCt(timestampToString(r.getCreateTime()));
            o.setCap(NumberToUtils.doubleToFloat2Decimal(v.getCpa(), NumConstant.INT_TWO));
            list.add(o);
        }

        response.setData(list);
        response.setRetCode(ServerConstant.SUCCESS);
        response.setRetMsg(ServerConstant.SUCCESS_MSG);

        return response;
    }

    @Override
    public BatteryDetailsRsp batteryDetailsHistoryQuery(BatteryDetailsHistoryQueryReq request) {
        return batteryDetailsHistoryService.historyDetail(request);
    }

    @Override
    public BatteryDetailsRsp batteryDetailsQuery(String cabinetNoStr, String door, Integer lineNo, Integer channelNo, Integer pageNum, Integer pageSize) {
        var response = new BatteryDetailsRsp();

        if (StringUtils.isBlank(cabinetNoStr)) {
            cabinetNoStr = "0";
        }

        var cabinetNo = Integer.parseInt(cabinetNoStr);
        pageNum = Math.max(pageNum, NumConstant.INT_ONE);
        var limit = Math.max(pageSize, NumConstant.INT_HUNDRED);
        if (StringUtils.isBlank(door) || null == lineNo || null == channelNo) {
            return response;
        }

        var boardConfig = boardConfigMapper.queryByDoorAndChannelNo(door, lineNo, channelNo);
        if (null == boardConfig) {
            log.error("查询电芯曲线[{}]-[{}]-[{}]的阶段统计数据失败,原因:电芯不存在", door, lineNo, channelNo);
            return response;
        }

        var bn = batchNoService.queryOne(cabinetNo);
        var batchNo = null != bn && StringUtils.isNotBlank(bn.getBatchNo()) ? bn.getBatchNo() : null;
        if (StringUtils.isBlank(batchNo)) {
            log.info("查询电芯曲线cn[{}]-bn[{}]-cnn[{}]的阶段统计数据失败,原因:没有找到批次号", cabinetNo, boardConfig.getAddress(), channelNo);
            return response;
        }

        var tableName = TableConstant.TABLE_REAL_TIME + boardConfig.getAddress();
        var count = tableMapper.queryRealTimeCountByBatchNo(tableName, cabinetNo, boardConfig.getAddress(), channelNo, batchNo);
        if (count <= NumConstant.INT_ZERO) {
            return response;
        }

        var vdo = tableMapper.queryRealTimeByBatchNoAndLimit(tableName, cabinetNo, boardConfig.getAddress(), channelNo, batchNo, pageNum * limit - limit, limit);
        if (CollectionUtils.isEmpty(vdo)) {
            response.setRetCode("20002");
            response.setRetMsg(ServerConstant.ERROR_MSG);
            return response;
        }

        List<BatteriesDetails> list = new ArrayList<>();
        response.setDataCount(count);
        var pageCount = (int) Math.ceil((double) count / limit);
        response.setPageNumCount(pageCount);
        for (var r : vdo) {
            byte[] data;
            try {
                data = compressionService.decompress(r.getData());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            var v = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
            if (v == null) {
                continue;
            }

            var o = new BatteriesDetails();
            o.setType(v.getCty());
            o.setC((float) v.getC());
            o.setV((float) v.getV());
            o.setAt(r.getTime());
            o.setCt(timestampToString(r.getCreateTime()));
            o.setCap(NumberToUtils.doubleToFloat2Decimal(v.getCpa(), NumConstant.INT_TWO));
            list.add(o);
        }

        response.setData(list);
        response.setRetCode(ServerConstant.SUCCESS);
        response.setRetMsg(ServerConstant.SUCCESS_MSG);

        return response;
    }

    @Override
    public BatteryDetailsRsp batteryDetailsQueryByAt(String cabinetNoStr, String door, Integer lineNo, Integer channelNo, Long at) {
        var response = new BatteryDetailsRsp();

        if (StringUtils.isBlank(cabinetNoStr)) {
            cabinetNoStr = "0";
        }
        var cabinetNo = Integer.parseInt(cabinetNoStr);
        if (StringUtils.isBlank(door) || null == lineNo || null == channelNo) {
            return response;
        }

        var boardConfig = boardConfigMapper.queryByDoorAndChannelNo(door, lineNo, channelNo);
        if (null == boardConfig) {
            log.error("查询电芯曲线详情[{}]-[{}]-[{}]的阶段统计数据失败,原因:电芯不存在", door, lineNo, channelNo);
            return response;
        }

        //var bn = batchNoService.queryOne(cabinetNo);
        var tableName = TableConstant.TABLE_REAL_TIME + boardConfig.getAddress();
        var cacheKey = CaffeineUtil.BATCH_NO_KEY + CaffeineUtil.getCacheKey(cabinetNo, boardConfig.getAddress(), boardConfig.getChannelNo());
        String batchNo = CaffeineUtil.get(cacheKey);
        if (StringUtils.isBlank(batchNo)) {
            var rt = tableMapper.queryRealTimeLast(tableName, cabinetNo, boardConfig.getAddress(), boardConfig.getChannelNo());
            batchNo = null != rt && StringUtils.isNotBlank(rt.getBatchNo()) ? rt.getBatchNo() : null;
            if (StringUtils.isBlank(batchNo)) {
                log.error("查询电芯曲线详情cn[{}]-bn[{}]-cnn[{}]的阶段统计数据失败,原因:没有找到批次号", cabinetNo, boardConfig.getAddress(), channelNo);
                return response;
            } else {
                CaffeineUtil.set(cacheKey, batchNo, 60);
            }
        }

        var count = tableMapper.queryRealTimeCountByAtAndBatchNo(tableName, cabinetNo, boardConfig.getAddress(), channelNo, batchNo, at);
        if (count <= NumConstant.INT_ZERO) {
            log.info("曲线实时推送[增量推送]总数为0,cab:{}-{}-{}-{}", cabinetNo, boardConfig.getAddress(), channelNo, at);
            return response;
        }

        var vdo = tableMapper.queryRealTimeByAtAndBatchNo(tableName, cabinetNo, boardConfig.getAddress(), channelNo, batchNo, at);
        if (CollectionUtils.isEmpty(vdo)) {
            response.setRetCode("20002");
            response.setRetMsg(ServerConstant.ERROR_MSG);
            return response;
        }

        List<BatteriesDetails> list = new ArrayList<>();
        for (var r : vdo) {
            byte[] data;
            try {
                data = compressionService.decompress(r.getData());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            var v = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
            if (v == null) {
                continue;
            }

            var o = new BatteriesDetails();
            o.setType(v.getCty());
            o.setC((float) v.getC());
            o.setV((float) v.getV());
            o.setAt(r.getTime());
            o.setCt(timestampToString(r.getCreateTime()));
            o.setCap(NumberToUtils.doubleToFloat2Decimal(v.getCpa(), NumConstant.INT_TWO));
            list.add(o);
        }

        response.setData(list);
        response.setRetCode(ServerConstant.SUCCESS);
        response.setRetMsg(ServerConstant.SUCCESS_MSG);

        return response;
    }

    private String timestampToString(long timestamp) {
        var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        return sdf.format(new Date(timestamp));
    }

    private Long getCreateTime(Integer cabinetNo, Integer boardAddress, Integer channelNo) {
        var key = KeyUtil.commandOperateKey(cabinetNo, boardAddress, channelNo);
        var vo = operationVoCacheService.getOperationVo(key);
        if (vo == null) {
            var op = operationDetailMapper.findOneDetailLast(String.valueOf(cabinetNo), boardAddress, channelNo);
            return op != null && op.getFirstOrderTime() != null ? op.getFirstOrderTime() : null;
        }

        var operationDetail = operationDetailMapper.findOneDetailByOrderNo(
                vo.getCabinetNo(),
                vo.getBoardAddress(),
                vo.getCellNum(),
                vo.getStepId().intValue()
        );

        if (operationDetail == null) {
            return null;
        }

        return operationDetail.getFirstOrderTime() == null ? operationDetail.getCreateTime() : operationDetail.getFirstOrderTime();
    }
}